// SPDX-License-Identifier: GPL-2.0 or GPL-3.0
// Copyright © 2018-2019 Ariadne Devos
/* sHT -- (x86) compare values without misinforming the compiler */

/* This is transcluded from <sHT/test.h>. */

/* Operand order: first the source, then the destination.
  E.g., cmp $3,%rdx.

  When compiling, the following diagnostic was print:
  > Error: too many memory references for cmp
  Use the alternative constraints feature of GCC to
  avoid this problem.

  When reading AMD and probably Intel documentation:
  'greater' is for signed integers, 'above' for unsigned integers.

  %: commutative */

#define _sHT_ge(a, b, correct) \
	__asm__ goto ("cmp %1,%0;jae %l[" #correct "]" : : "r,m" (a), "erm,er" (b) : "cc" : correct)
#define _sHT_eq(a, b, correct) \
	__asm__ goto ("cmp %1,%0;je %l[" #correct "]" : : "%r,%m" (a), "erm,er" (b) : "cc" : correct)
#define _sHT_neq(a, b, correct) \
	__asm__ goto ("cmp %1,%0;jne %l[" #correct "]" : : "%r,%m" (a), "erm,er" (b) : "cc" : correct)
#define _sHT_eq_bool(a, b, c) \
	__asm__ ("cmp %2,%1;sete %0" : "=r,r" (c) : "%r,%m" (a), "erm,er" (b) : )

#define _sHT_lt(a, b, correct) \
	__asm__ goto ("cmp %1,%0;jb %l[" #correct "]" : : "r,m" (a), "erm,er" (b) : "cc" : correct)
#define _sHT_gt(a, b, correct) \
	__asm__ goto ("cmp %1,%0;ja %l[" #correct "]" : : "r,m" (a), "erm,er" (b) : "cc" : correct)

/* testl is supposedlu smaller than cmp */
#define _sHT_zero_p(a, correct) \
	__asm__ goto ("test %0,%0;je %l[" #correct "]" : : "r" (a) : "cc" : correct)
#define _sHT_nonzero_p(a, correct) \
	__asm__ goto ("test %0,%0;jnz %l[" #correct "]" : : "r" (a) : "cc" : correct)
/* cmp %0,%0 does not work! Try tests/cmp. */
#define _sHT_lt0(a, correct) \
	__asm__ goto ("test %0,%0;js %l[" #correct "]" : : "r" (a) : "cc" : correct)
#define _sHT_and_any_p(a, b, correct) \
	__asm__ goto ("test %1,%0;jnz %l[" #correct "]" : : "%rm" (a), "er" (b) : "cc" : correct)
#define _sHT_and_none_p(a, b, correct) \
	__asm__ goto ("test %1,%0;je %l[" #correct "]" : : "%rm" (a), "er" (b) : "cc" : correct)

#define _sHT_msb_set(a, correct) \
	__asm__ goto ("test %0,%0;js %l[" #correct "]" : : "r" (a) : "cc" : correct)
#define _sHT_msb_unset(a, correct) \
	__asm__ goto ("test %0,%0;jns %l[" #correct "]" : : "r" (a) : "cc" : correct)
